
#########################################################
# Basic OOP, Ruby libraries, introspection
#########################################################

# 1. Finger Exercise

class Numeric

  def squared
    self * self
  end
    
end

9.squared
# => 81



require 'time'
require 'movie'

# 2. 
# Time class contains a method called "parse". 
# "1:00 pm" is a String which does not have a parse method


class String
  def parse
    Time.parse(self)
  end
end

# 3. See movie.rb -> Movie.initialize

# 4. See movie.rb -> Movie.name_and_showtime
      

$movies[1].name_and_showtime
# => "Orphan: already started at 04:05 PM"
$movies[3].name_and_showtime
# => "GI Joe: already started at 01:05 PM"
      

#########################################################      
# Modules       
#########################################################

# 1. See movie.rb -> Movie.<=>      
      

# 2. See movie.rb -> class Movie
      
$movies[1].between?($movies[0], $movies[2])
# => true

$movies[0].between?($movies[1], $movies[2])
# => false


# 3.
# $movies.sort works because sort (defined by the Array class) relies on the <=> operator
# being defined for objects in the array that will be compared. 
# Since we have defined it for type Movie, sort can now order all objects of this type 

$movies.sort 
# =>  [#<Movie:0x5a56b8 @name="Rocky  Horror",  @showtime=Thu Sep  10 00:00:00  -0700
# 2009>,  #<Movie:0x5a15cc   @name="District  9",   @showtime=Thu  Sep   10  11:00:00   -0700  2009>,
# #<Movie:0x5bcbc4  @name="Orphan",  @showtime=Thu  Sep  10 13:00:00  -0700  2009>,  #<Movie:0x5b147c
# @name="GI Joe",  @showtime=Thu Sep  10 13:05:00 -0700  2009>, #<Movie:0x59d544  @name="District 9",
# @showtime=Thu Sep  10 15:00:00 -0700  2009>, #<Movie:0x5b8ee8 @name="Orphan", @showtime=Thu  Sep 10
# 16:05:00 -0700 2009>,  #<Movie:0x5ad6ec @name="GI Joe", @showtime=Thu Sep 10  16:30:00 -0700 2009>,
# #<Movie:0x5a9920  @name="GI  Joe", @showtime=Thu  Sep  10  18:50:00 -0700  2009>,  #<Movie:0x5b51d0
# @name="Orphan",        @showtime=Thu        Sep        10       19:00:00        -0700        2009>]
# 

#########################################################
# Higher-order functions & functional programming
#########################################################

# 1. See movie.rb -> Enumerable::group_by

 
a = %w(apple banana cherry alice bob carol alpha bravo charlie) 
# => ["apple", "banana", "cherry", "alice", "bob", "carol", "alpha", "bravo", "charlie"]
a.group_by { |x| x[0,1].to_s }  
# => {"a"=>["apple", "alice", "alpha"], "b"=>["banana", "bob", "bravo"], "c"=>["cherry", "carol", "charlie"]}
class String ; def first_letter ; self[0,1].to_s ; end ; end
# => nil
a.group_by { |x| x.first_letter }
# => {"a"=>["apple", "alice", "alpha"], "b"=>["banana", "bob", "bravo"], "c"=>["cherry", "carol", "charlie"]}

# 2. See movie.rb -> Enumerable::group_by

$movies.group_by {|movie| movie.name}
# => {"District 9"=>[#<Movie:0x5a15cc @name="District 9", @showtime=Thu Sep 10 11:00:00 -0700 2009>, #<Movie:0x59d544 @name="District 9", @showtime=Thu Sep 10 15:00:00 -0700 2009>], 
#     "Orphan"=>[#<Movie:0x5bcbc4 @name="Orphan", @showtime=Thu Sep 10 13:00:00 -0700 2009>, #<Movie:0x5b8ee8 @name="Orphan", @showtime=Thu Sep 10 16:05:00 -0700 2009>, #<Movie:0x5b51d0 @name="Orphan", @showtime=Thu Sep 10 19:00:00 -0700 2009>], 
#     "GI Joe"=>[#<Movie:0x5b147c @name="GI Joe", @showtime=Thu Sep 10 13:05:00 -0700 2009>, #<Movie:0x5ad6ec @name="GI Joe", @showtime=Thu Sep 10 16:30:00 -0700 2009>, #<Movie:0x5a9920 @name="GI Joe", @showtime=Thu Sep 10 18:50:00 -0700 2009>], 
#     "Rocky Horror"=>[#<Movie:0x5a56b8 @name="Rocky Horror", @showtime=Thu Sep 10 00:00:00 -0700 2009>]}
# 

# 3.
# 3.1
$movies.select {|movie| movie.showtime > Time.parse("5:00 pm") }
# 3.2
$movies.select {|movie| movie.showtime > Time.parse("5:00 pm") }.length
# 3.3
$movies.select {|movie| movie.showtime > Time.parse("5:00 pm") }.collect{|mov| mov.name}.uniq 
 

#########################################################
# Iterators
#########################################################

# 1. See movie.rb -> Range.each_even

x = (1..9)
# => 1..9

x.each_even { |n| puts n }
# 2
# 4
# 6
# 8
# => 1..9

# 2. See movie.rb -> Enumerable.each_grouped_by_first_letter

a = %w(apple banana cherry alice bob carol alpha bravo charlie)
# => ["apple", "banana", "cherry", "alice", "bob", "carol", "alpha", "bravo", "charlie"]
a.each_grouped_by_first_letter do |letter, words|
 puts "#{letter} : #{words.join(' ')}"
end
# a : apple alice alpha
# b : banana bob bravo
# c : cherry carol charlie
# => {"a"=>["apple", "alice", "alpha"], "b"=>["banana", "bob", "bravo"], "c"=>["cherry", "carol", "charlie"]} 
#  

#########################################################
# Extending classes
#########################################################

# See movie.rb -> class IndifferentHash

#########################################################
# Language extensions for convenience
#########################################################
 

def blank? (obj=nil)
  (defined? obj).nil? or obj.nil? or obj.empty?
end 
 
class String
  def blank?
    self.nil? or self.strip.empty?  
  end
end

class Object
  def blank?
    if self.respond_to?(:empty?) 
      self.empty?
    else
      self.nil?
    end
  end
end 
